package com.snail.common.excel.listener;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.ReadListener;
import com.snail.common.core.exception.ServiceException;
import com.snail.common.core.utils.SpringUtils;
import com.snail.common.core.utils.StringUtils;
import com.snail.common.core.utils.ValidationUtils;
import com.snail.common.excel.config.ExcelProperties;
import com.snail.common.excel.constants.ExcelConstants;
import com.snail.common.excel.utils.EasyExcelUtils;

import javax.validation.Validator;
import java.util.*;

import static com.alibaba.excel.converters.ConverterKeyBuild.buildKey;

/**
 * @Description: Excel导入监听接口
 * @Author: Snail
 * @CreateDate: 2023/8/15 17:39
 * @Version: V1.0
 */
public interface IExcelService<T> extends ReadListener<T> {

    @Override
    default void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
        Class<?> headClazz = context.currentReadHolder().excelReadHeadProperty().getHeadClazz();
        Map<Integer, Head> map = EasyExcelUtils.getHeadMap(headClazz, context.currentReadHolder().excelReadHeadProperty().getHeadMap(),context);
        context.currentReadHolder().excelReadHeadProperty().setHeadMap(map);
    }


    /**
     * 读取Excel每行数据
     *
     * @param t               行数据
     * @param analysisContext analysisContext
     */
    @Override
    default void invoke(T t, AnalysisContext analysisContext) {
        //第几行
        Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
        //存放数据
        Map<String, Object> custom = (Map<String, Object>) analysisContext.getCustom();
        if (custom == null) {
            custom = new HashMap<>(64);
        }
        //校验通过的数据
        List<T> successList = MapUtil.get(custom, ExcelConstants.SUCCESS_KEY, List.class, new ArrayList());
        //校验通过的条数
        Integer successNum = MapUtil.get(custom, ExcelConstants.SUCCESS_NUM_KEY, Integer.class, 0);
        //校验不通过的条数
        Integer failureNum = MapUtil.get(custom, ExcelConstants.FAILURE_NUM_KEY, Integer.class, 0);
        //错误信息
        StringBuilder errorMsg = new StringBuilder(MapUtil.get(custom, ExcelConstants.ERROR_MSG_KEY, String.class, ""));
        //业务数据校验
        String error = checkExcelData(t);
        if (StringUtils.isNotBlank(error)) {
            errorMsg.append("第").append(rowIndex).append("条").append(error);
            failureNum++;
        } else {
            successList.add(t);
            successNum++;
        }
        //获取Excel导入、导出配置类
        ExcelProperties properties = SpringUtils.getBean(ExcelProperties.class);
        if (!properties.importAll) {
            if (successList.size() == properties.getImportNum()) {
                saveExcelData(successList);
                successList.clear();
            }
        }
        //数据校验是否的信息
        custom.put(ExcelConstants.ERROR_MSG_KEY, errorMsg.toString());
        //数据校验通过的数据信息
        custom.put(ExcelConstants.SUCCESS_KEY, successList);
        //数据校验通过的条数
        custom.put(ExcelConstants.SUCCESS_NUM_KEY, successNum);
        //数据校验失败的条数
        custom.put(ExcelConstants.FAILURE_NUM_KEY, failureNum);
        //自定义信息放入analysisContext
        analysisContext.readWorkbookHolder().setCustomObject(custom);
    }

    /**
     * Excel读取完成后
     *
     * @param analysisContext analysisContext
     */
    @Override
    default void doAfterAllAnalysed(AnalysisContext analysisContext) {
        ExcelProperties properties = SpringUtils.getBean(ExcelProperties.class);
        boolean importAll = properties == null || properties.importAll;
        //数据验证信息
        Map<String, Object> custom = (Map<String, Object>) analysisContext.getCustom();
        //错误信息
        String errorMsg = MapUtil.get(custom, ExcelConstants.ERROR_MSG_KEY, String.class);
        //校验通过的数据
        List<T> successList = MapUtil.get(custom, ExcelConstants.SUCCESS_KEY, List.class, new ArrayList());
        //校验通过的条数
        Integer successNum = MapUtil.get(custom, ExcelConstants.SUCCESS_NUM_KEY, Integer.class, 0);
        //校验不通过的条数
        Integer failureNum = MapUtil.get(custom, ExcelConstants.FAILURE_NUM_KEY, Integer.class, 0);
        //校验失败返回异常信息
        if (StringUtils.isNotEmpty(errorMsg) && importAll) {
            throw new ServiceException(StringUtils.format(ExcelConstants.ALL_ERROR_MSG, failureNum, errorMsg));
        }
        if (CollectionUtil.isNotEmpty(successList)) {
            saveExcelData(successList);
        }
        if (StringUtils.isNotEmpty(errorMsg) && !importAll) {
            throw new ServiceException(StringUtils.format(ExcelConstants.ERROR_MSG, successNum, failureNum, errorMsg));
        }
    }


    /**
     * 校验Excel数据
     *
     * @param t 数据
     * @return 错误信息
     */
    default String checkExcelData(T t) {
        StringBuffer error = new StringBuffer();
        ValidationUtils.checkProperty(SpringUtils.getBean(Validator.class), t, excludeCheckFiled(t), t.getClass(), error);
        return error.toString();
    }

    /**
     * 排除不需要校验
     *
     * @param t
     * @return
     */
    default List<String> excludeCheckFiled(T t) {
        return Collections.emptyList();
    }


    /**
     * 报错Excel的数据
     *
     * @param dataList 数据
     */
    void saveExcelData(List<T> dataList);
}
